package com.behelpful.common.core.enums;

import com.behelpful.common.core.exceptions.IRuntimeException;
import com.behelpful.common.core.exceptions.ParamException;
import com.behelpful.common.core.result.ErrorResult;
import com.behelpful.common.core.result.FailedResult;
import com.behelpful.common.core.jackson.IEnumDeserializer;
import com.behelpful.common.core.utils.ExceptionUtil;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.SneakyThrows;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 自定义系列化枚举超类
 *
 * @author Alay
 * @date 2021-08-17 09:41
 * @project be-helpful
 * @since
 */
@JsonDeserialize(using = IEnumDeserializer.class)
public interface IEnum<T extends Serializable> extends Serializable {

    IRuntimeException EXCEPTION = new ParamException(FailedResult.NOT_PERMITTED);

    /**
     * 获取枚举编码
     *
     * @return
     */
    int getCode();

    /**
     * 获取枚举值
     *
     * @return
     */
    default T getValue() {
        throw EXCEPTION;
    }

    /**
     * 获取枚举名称
     *
     * @return
     */
    default String getName() {
        return this.name();
    }

    /**
     * 获取枚举名称
     *
     * @return
     */
    String name();

    /**
     * 根据枚举名称获取枚举对象
     *
     * @param clazz
     * @param name
     * @param <E>
     * @return
     */
    @SneakyThrows
    static <E extends Enum<E> & IEnum> E sourceOf(Class<E> clazz, String name) {
        Method valuesMethod = clazz.getMethod("values");
        E[] enumInstanceArr = (E[]) valuesMethod.invoke(null);
        for (E enumInstance : enumInstanceArr) {
            if (Objects.equals(enumInstance.name(), name)) {
                return enumInstance;
            }
        }
        throw ExceptionUtil.create(IRuntimeException.class, ErrorResult.PARAMETER_ERROR);
    }

    /**
     * 根据编码获取枚举对象
     *
     * @param clazz
     * @param code
     * @param <E>
     * @return
     */
    @SneakyThrows
    static <E extends Enum<E> & IEnum> E codeOf(Class<E> clazz, int code) {
        Method valuesMethod = clazz.getMethod("values");
        E[] enumInstanceArr = (E[]) valuesMethod.invoke(null);
        for (E enumInstance : enumInstanceArr) {
            if (code == enumInstance.getCode()) {
                return enumInstance;
            }
        }
        throw ExceptionUtil.create(IRuntimeException.class, ErrorResult.PARAMETER_ERROR);
    }

}
